NTQQ(iOS)
参考了 https://github.com/QQBackup/QQ-History-Backup/issues/9 以及 https://github.com/QQBackup/qq-win-db-key 中的各平台教程。
I 环境配置
越狱环境
在 iOS 设备上操作
Cydia / Sileo / Zebra 添加 Frida 官方软件源
https://build.frida.re
安装
Frida
包启动 Frida 服务器
在终端(NewTerm 之类的终端App,或SSH)运行:
frida-server -v
如果端口被占用,更换其他端口,如:
frida-server --listen='0.0.0.0:27043' -v
启动 Frida 服务端。
命令前部加上
sudo
赋予 root 用户权限也许会更好
免越狱环境
需要有 TrollStore 巨魔 环境
开始
App 脱壳,可参考下一章节(需要得到完整的 IPA 安装包)
下载 Frida Gadget 动态链接库
frida-gadget-x.x.x-ios-universal.dylib.gz
并解压得到frida-gadget-ios-universal.dylib
注入 Frida Gadget 动态链接库,有两种方法,Sideloadly 更方便且支持 Windows,命令行方式 optool 需要在 macOS 环境下进行
方式一、使用 Sideloadly 注入 Frida Gadget
直接照图进行配置:
- 不允许自动更改 Bundle ID
- 开启文件共享(即开放 App 沙盒 Documents 目录到系统自带的文件 App)
- 注入动态链接库
- 仅导出 IPA
然后点击 Start 开始导出
方式二、使用 optool 注入 Frida Gadget
解压脱壳得到的 IPA 安装包
安装 optool,这里需要使用
xcodebuild
命令
git clone https://github.com/alexzielenski/optool.git
cd optool
git submodule update --init --recursive
xcodebuild
ln -s $PWD/build/Release/optool /usr/local/bin/optool
- 将前面下载的
frida-gadget-ios-universal.dylib
放入 IPA 解压目录下的Payload/QQ.app/Frameworks
目录
cp frida-gadget-ios-universal.dylib Payload/QQ.app/Frameworks
- 用 optool 把动态链接库加载命令插入到 QQ 主程序中(此处路径无法自动补全,注意不要打错了)
optool install -c load -p "@executable_path/Frameworks/frida-gadget-ios-universal.dylib" -t Payload/QQ.app/QQ
运行成功的输出:
Found thin header...
Load command already exists
Successfully inserted a LC_LOAD_DYLIB command for arm64
Writing executable to Payload/QQ.app/QQ...
为了方便后续导出聊天记录数据库等文件,需要修改 App 配置,允许用户通过系统自带的文件 App 访问 App 沙盒 Documents 目录,具体操作可以网上查询(
重新打包 IPA,可以直接压缩
Payload
目录为 zip 归档,然后重命名文件后缀为ipa
,把重新打包好的 IPA 安装包发送到 iOS 设备
安装重新打包好的 IPA
发送重新打包好的 QQ IPA 安装包到 iOS 设备,使用 TrollStore 巨魔 进行安装,如果提示安装失败,应用已存在,选择强制安装
需要使用巨魔的原因:附带了 Frida Gadget 的 QQ 安装包需要以覆盖,或者更新的方式安装到设备,这样它才能读取到聊天记录,不然系统会分配新的沙盒空间。为了实现这一点,App Bundle ID 需要保持不变,即
com.tencent.mqq
,但如果使用腾讯的com.tencent.*
作为 Bundle ID,在签名过程中就会失败,因此需要绕过签名,即使用 TrollStore 安装。
将 iOS 设备有线连接至 PC,可以自行用 frida-ps
等工具测试一下 Frida 服务器是否正常工作(无线连接等可以参考 Frida 文档 - Gadget)
II 反编译
如果你的 QQ 版本和脚本 ios_get_key.js 内注释的版本一致,可直接跳过进入下一步
如果 QQ 版本不一致,但下一步的脚本 ios_get_key.js 可以正常使用,也可以忽略本节
App 脱壳
可选工具
- dumpdecrypted (https://github.com/stefanesser/dumpdecrypted)
- frida-ios-dump (https://github.com/AloneMonkey/frida-ios-dump)
- AppsDump2(有图形界面的App,用起来很方便,不过似乎找不到它的仓库链接)
- ...
只需要得到脱壳后的 Mach-O 二进制主程序即可,不需要完整的 IPA 安装包。
反编译
本篇示例
- iOS QQ v9.0.1.620
- SQLCipher v4.5.1
主要目的是获取 sqlite3_key_v2
函数位置,页大小、纯文本文件大小、PBKDF2 迭代次数等通常是固定的。
用例如 IDA 的反编译工具反编译脱壳得到的 Mach-O 二进制主程序
搜索二进制片段
sqlite3_key_v2
,可以找到日志文本,从而定位到SQLCipher C API 的sqlite3_key_v2
函数在程序中的位置。第三个参数即为数据库密钥,根据传入的其他实参,还能得到更多信息。
int sqlite3_key_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey);
得到目标函数的位置为 000000010DA1BFB4
。由于IDA基址设为了 0000000100000000
,两者相减,
得到偏移量为 0xDA1BFB4
,将其设置为脚本文件 ios_get_key.js 中的 SQLLiteKeyV2Offset
的值。
// ios_get_key.js
const SQLLiteKeyV2Offset = 0xDA1BFB4;
- 根据调用关系
sqlite3CodecAttach
->sqlcipher_codec_ctx_init
->sqlcipher_codec_ctx_set_pagesize
可以确定页大小为4096
- 根据调用关系
sqlite3CodecAttach
->sqlcipher_codec_ctx_init
->sqlcipher_codec_ctx_set_plaintext_header_size
,
用 Frida hooksqlcipher_codec_ctx_set_plaintext_header_size
函数,可以确定纯文本文件大小为0
III Frida 附加到 QQ 进程,获取密钥
- 在 PC 上安装 frida(确保 Python 已安装)
# pipx 可以把包安装到隔离的环境,避免依赖冲突
pip install pipx
pipx install frida
frida --version
iOS 上没有编译好的 frida 工具(只有 frida-server),因此需要电脑
有试过自己编译,但总是会因为 macOS/iOS 的平台判定什么的导致运行失败(
下载 ios_get_key.js(如果上一步已经下载过了可以跳过)
iOS 设备打开 QQ App
PC Frida 连接至 iOS 设备,终端运行命令以附加脚本到 QQ 进程
连接方式有两种:
- USB 连接:
frida -U QQ -l ios_get_key.js
- 网络连接
frida -H <设备IP地址>:<frida-server端口号> QQ -l ios_get_key.js
IP地址为iOS设备的IP地址,端口号在第一步配置过。例如:
frida -H 192.168.1.163:27043 QQ -l ios_get_key.js
iOS frida-server 只能附加到已有进程,不能以 spawn 方式生成进程,原因暂不知
iOS 设备 QQ 进行登录操作
查看 PC 终端 输出内容,可以看到一条条信息被输出,其中
pKey
为数据库密钥zFilename
为对应的数据库文件所在路径
输出的数据库信息已经过筛选。
例如:
+------------
¦- db: 0x152ec8710
¦- *zDb: main
¦- *pkey: d3c1d0f05b2cxxxxxxxxxxc1ac161c29
¦- *pkey-hex: ...
¦- nKey: 32
¦+
¦- zFilename: /var/mobile/Containers/Data/Application/22675923-xxxx-xxxx-xxxx-C1CB389E8E22/Documents/QQNT/DB/nt_db/nt_qq_15207xxxxxxxxxxxxxxxxx0d0be/nt_msg.db
+------------
¦- db: 0x152ec8710
¦- *zDb: main
¦- *pkey: d3c1d0f05b2cxxxxxxxxxxc1ac161c29
¦- *pkey-hex: ...
¦- nKey: 32
¦+
¦- zFilename: /var/mobile/Containers/Data/Application/22675923-xxxx-xxxx-xxxx-C1CB389E8E22/Documents/QQNT/DB/nt_db/nt_qq_15207xxxxxxxxxxxxxxxxx0d0be/guild_msg.db
+------------
复制其中的 pKey
和 zFilename
- 从 iOS 设备下载数据库文件
- 越狱用户可使用 SFTP 或 Filza App
- 免越狱方式直接用 iOS 自带的文件 App 查看
路径为上一步的 zFilename
所在目录的路径
/var/mobile/Containers/Data/Application/22675923-xxxx-xxxx-xxxx-C1CB389E8E22/Documents/QQNT/DB/nt_db/nt_qq_15207xxxxxxxxxxxxxxxxx0d0be
该目录下有数个数据库,除了一般的聊天记录以外还有(QQ频道记录?)更多数据。
- 打开数据库
请参考 NTQQ 解密数据库。